﻿using System.Web.Script.Serialization;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using System.IO;
using FiddlerExUtils.Helper;
using Fiddler;
using Newtonsoft.Json.Linq;
using System.Text;
using System.Windows.Forms;
using Fiddler.WebFormats;
using System.Data;
using System.Globalization;
using System.Collections;
using System.Xml;
using System.Linq;
using FiddlerExUtils.Components;
using Microsoft.Win32;
using System.Security.Cryptography;
using System.Reflection;

namespace FiddlerExUtils.Tools
{
    public class CommonFunction
    {

        /// <summary>
        /// 双缓冲，解决控件闪烁问题
        /// </summary>
        /// <param name="dgv"></param>
        /// <param name="setting"></param>
        public static void DoubleBuffered(Control dgv, bool setting)
        {
            Type dgvType = dgv.GetType();
            PropertyInfo pi = dgvType.GetProperty("DoubleBuffered",
                BindingFlags.Instance | BindingFlags.NonPublic);
            pi.SetValue(dgv, setting, null);
        }

        /// <summary>
        /// 替换表情等不识别字符
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ReplaceSpecialString(string str)
        {
            string result = Regex.Replace(str, @"\p{Cs}", "");
            //result = this.JsonPre(result);
            return result;
        }

        /// <summary>
        /// 判断字符串是否为JSON格式
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static bool IsJson(string json)
        {
            json = json.Trim();
            if (json == "")
            {
                return false;
            }
            if (json.StartsWith("[") && json.Trim().EndsWith("]"))
            {
                json = json.TrimStart('[').TrimEnd(']').Trim();
            }
            JavaScriptSerializer js = new JavaScriptSerializer();
            try
            {
                Dictionary<string, object> dic = js.Deserialize<Dictionary<string, object>>(json);
                return true;
            }
            catch (Exception)
            {
                //Fiddler.FiddlerApplication.Log.LogString("JSON内容格式不正确：" + json + "\n" + ex);
                return false;
            }
        }

        /// <summary>
        /// 获取Json节点值，注：节点字段名区分大小写
        /// </summary>
        /// <param name="json_string"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public static ArrayList GetJsonValue(string json_string, string node)
        {
            ArrayList result = new ArrayList();
            if (IsJson(json_string) && node != "")
            {
                JavaScriptSerializer js = new JavaScriptSerializer();
                try
                {
                    Dictionary<string, object> dic = js.Deserialize<Dictionary<string, object>>(json_string);
                    if (dic != null)
                    {
                        ArrayList res = new ArrayList();
                        result = Test(dic, node, res);
                    }
                    else
                    {
                        Fiddler.FiddlerApplication.Log.LogString("反序列化失败：" + json_string);
                        result.Add("");
                        return result;
                    }
                    if (result.Count == 0)
                    {
                        //Fiddler.FiddlerApplication.Log.LogString("未获取到：" + node + "的值\n" + json_string);
                        result.Add("");
                    }
                    return result;
                }
                catch (Exception e)
                {
                    //Fiddler.FiddlerApplication.Log.LogString("获取" + node + "字段值失败：" + e.ToString());
                    result.Add("");
                    return result;
                }
            }
            result.Add("");
            return result;
        }

        public static ArrayList Test(Dictionary<string, object> dictionary, string node, ArrayList result)
        {
            foreach (KeyValuePair<string, object> item in dictionary)
            {
                try
                {
                    dictionary = (Dictionary<string, object>)(item.Value);
                    if (dictionary != null)
                    {
                        Test(dictionary, node, result);
                    }
                }
                catch (Exception e)
                {
                    if (item.Value is ArrayList)//判断子节点是否是数组
                    {
                        foreach (object obj in (ArrayList)item.Value)
                        {
                            try
                            {
                                dictionary = (Dictionary<string, object>)(obj);
                                if (dictionary != null)
                                {
                                    Test(dictionary, node, result);
                                }
                            }
                            catch (Exception ex)
                            {
                            }
                        }
                    }
                    else if (item.Key.ToString() == node)
                    {
                        string value = item.Value.ToString();
                        result.Add(value);
                    }
                    else
                    {
                        //FiddlerApplication.Log.LogString("GetJsonValue(): " + node + " -- Node not found！");
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 转换成JSON缩进格式
        /// </summary>
        /// <param name="json">JSON字符串</param>
        /// <param name="isSort">是否按首字母重新排序</param>
        /// <returns></returns>
        public static string ConvertJsonString(string json, bool isSort = false)
        {
            json = json.Trim();
            if (IsJson(json))
            {
                try
                {
                    //排序
                    //json = isSort ? SortJson(json) : json;
                    //格式化json字符串
                    JsonSerializer serializer = new JsonSerializer();
                    TextReader tr = new StringReader(json);
                    JsonTextReader jtr = new JsonTextReader(tr);
                    object obj = serializer.Deserialize(jtr);
                    if (obj != null)
                    {
                        StringWriter textWriter = new StringWriter();
                        //dynamic synws = TextWriter.Synchronized(textWriter);
                        JsonTextWriter jsonWriter = new JsonTextWriter(textWriter)
                        {
                            Formatting = Newtonsoft.Json.Formatting.Indented,
                            Indentation = 4,
                            IndentChar = ' '
                        };
                        serializer.Serialize(jsonWriter, obj);
                        return textWriter.ToString();
                    }
                    else
                    {
                        return json;
                    }
                }
                catch (Exception e)
                {
                    FiddlerApplication.Log.LogString("ConvertJsonString:" + e.Message + "\n" + e.StackTrace);
                }
            }
            return json;
        }

        /// <summary>  
        /// JSON首字母排序  
        /// </summary>  
        /// <param name="jobj">原始JSON JToken.Parse(string json);</param>  
        /// <param name="obj">初始值Null</param>  
        /// <returns></returns>  
        public static string SortJson(string json)
        {
            //TODO 没有递归排序，只排了第一层
            var paramDic = JsonConvert.DeserializeObject<SortedDictionary<string, object>>(json);
            SortedDictionary<string, object> keyValues = new SortedDictionary<string, object>(paramDic);
            keyValues.OrderBy(m => m.Key);//升序 把Key换成Value 就是对Value进行排序,//keyValues.OrderByDescending(m => m.Key);//降序
            return JsonConvert.SerializeObject(keyValues);
        }

        private static dynamic GetSorObject(Object obj)
        {
            if (obj is JArray)
            {
                var list = new List<dynamic>();
                foreach (var item in (obj as JArray))
                {
                    list.Add(GetSorObject(item));
                }
                return list;
            }
            else
            {
                var paramDic = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(JsonConvert.SerializeObject(obj));
                var sortedDic = new SortedDictionary<string, dynamic>();
                for (int i = 0; i < paramDic.Count; i++)
                {
                    if (paramDic.ElementAt(i).Value is JArray || paramDic.ElementAt(i).Value is JObject)
                    {
                        sortedDic.Add(paramDic.ElementAt(i).Key, GetSorObject(paramDic.ElementAt(i).Value));
                    }
                    else
                    {
                        sortedDic.Add(paramDic.ElementAt(i).Key, paramDic.ElementAt(i).Value);
                    }
                }
                return sortedDic;
            }
        }

        /// <summary>
        /// XML字符串格式化
        /// </summary>
        /// <param name="XMLstring"></param>
        /// <returns></returns>
        public static string FormatXML(string XMLstring)
        {
            //校验是否是XML报文
            if (!XMLstring.Contains("<?xml version")) return XMLstring;
            XmlDocument xmlDocument = GetXmlDocument(XMLstring);
            return ConvertXmlDocumentTostring(xmlDocument);
        }

        public static string ConvertXmlDocumentTostring(XmlDocument xmlDocument)
        {
            MemoryStream memoryStream = new MemoryStream();
            XmlTextWriter writer = new XmlTextWriter(memoryStream, null)
            {
                Formatting = System.Xml.Formatting.Indented//缩进
            };
            xmlDocument.Save(writer);
            StreamReader streamReader = new StreamReader(memoryStream);
            memoryStream.Position = 0;
            string xmlString = streamReader.ReadToEnd();
            streamReader.Close();
            memoryStream.Close();
            return xmlString;
        }

        public static XmlDocument GetXmlDocument(string xmlString)
        {
            XmlDocument document = new XmlDocument();
            document.LoadXml(xmlString);
            return document;
        }

        /// <summary>
        /// 获取目标节点条件的JSON Path值；
        /// </summary>
        /// <param name="oTN"></param>
        /// <returns></returns>
        internal static string GetTreeNodeJSONPath(TreeNode oTN)
        {
            if (oTN.Tag == null && oTN.Level >= 2)
            {
                string result = ""; //JSON Path值
                string rootNode = ""; //JSON根节点

                TreeNode currentNode;
                TreeNode parentNode;

                string currentNodeText = "";
                string parentNodeText = "";

                currentNode = oTN;
                parentNode = oTN.Parent;

                currentNodeText = currentNode.Text;
                parentNodeText = parentNode.Text;
                rootNode = currentNode.FullPath.Split('\\')[1];

                int currentNodeIndex;
                int parentNodeIndex;

                if (currentNode.Level <= 3)
                {
                    if (currentNodeText.Contains("="))
                    {
                        if (parentNodeText.Contains("{"))
                        {
                            parentNodeIndex = Convert.ToInt16(parentNode.Text.Split('{')[1].Split('}')[0]);
                            result = "$." + rootNode + "[" + parentNodeIndex + "]" + "." + currentNodeText.Split('=')[0];
                        }
                        else if (parentNodeText != rootNode)
                        {
                            result = "$." + rootNode + "." + parentNodeText + "." + currentNodeText.Split('=')[0];
                        }
                        else
                        {
                            result = "$." + rootNode + "." + currentNodeText.Split('=')[0];
                        }
                    }
                    else if (currentNodeText.Contains("{"))
                    {
                        currentNodeIndex = Convert.ToInt16(currentNodeText.Split('{')[1].Split('}')[0]);

                        if (parentNodeText != rootNode)
                        {
                            result = "$." + rootNode + "." + parentNodeText + "[" + currentNodeIndex + "]";
                        }
                        else
                        {
                            result = "$." + rootNode + "[" + currentNodeIndex + "]";
                        }
                    }
                    else
                    {
                        if (parentNodeText != rootNode)
                        {
                            result = "$." + rootNode + "." + parentNodeText + "." + currentNodeText;
                        }
                        else
                        {
                            result = "$." + rootNode + "." + currentNodeText;
                        }
                    }
                }
                else
                {
                    if (currentNodeText.Contains("="))
                    {
                        if (parentNodeText.Contains("{"))
                        {
                            result = "$." + rootNode + ".." + parentNode.Parent.Text + "[@." + currentNodeText.Split('=')[0] + " is \"" + currentNodeText.Split('=')[1] + "\"]." + currentNodeText.Split('=')[0];
                        }
                        else
                        {
                            result = "$." + rootNode + ".." + parentNode.Text + "[@." + currentNodeText.Split('=')[0] + " is \"" + currentNodeText.Split('=')[1] + "\"]." + currentNodeText.Split('=')[0];
                        }
                    }
                    else if (currentNodeText.Contains("{"))
                    {
                        currentNodeIndex = Convert.ToInt16(currentNodeText.Split('{')[1].Split('}')[0]);
                        result = "$." + rootNode + ".." + parentNodeText + "[" + currentNodeIndex + "]";
                    }
                    else
                    {
                        if (parentNodeText.Contains("{"))
                        {
                            parentNodeIndex = Convert.ToInt16(parentNode.Text.Split('{')[1].Split('}')[0]);
                            result = "$." + rootNode + ".." + parentNode.Parent.Text + "[" + parentNodeIndex + "]." + currentNodeText;
                        }
                        else
                        {
                            result = "$." + rootNode + ".." + parentNode.Text + "[@." + currentNodeText + " is \"\"]." + currentNodeText;
                        }
                    }
                }

                FiddlerApplication.Log.LogString(currentNodeText + " --> level: " + currentNode.Level + "  Copied JSON Path: " + result);

                return result;
            }

            return oTN.Tag as string;
        }

        /// <summary>
        /// 获取JSON节点值
        /// </summary>
        /// <param name="json"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string GetJsonValueWithPath(string json, string path)
        {
            try
            {
                JObject jsonObject = JObject.Parse(json);
                return jsonObject.SelectToken(path).ToString();
            }
            catch (Exception)
            {
                return "";
            }
        }

        /// <summary>
        /// WebBrowser的非JSON数据
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string GetDocumentTextWithoutJson(string content)
        {
            string html = "<html>\r\n" +
                "	<head>\r\n" +
                "		<meta name=\"viewport\" content=\"width=device-width, minimum-scale=0.1\">\r\n" +
                "		<title>JsonViewer</title>\r\n" +
                "		<style>\r\n" +
                "			body {\r\n" +
                "				font-family: Lucida Console, Georgia;\r\n" +
                "				font-size: 13px;\r\n" +
                "				background-color: #ECECEC;\r\n" +
                "				color: #000000;\r\n" +
                //"				border: solid 1px #CECECE;\r\n" +
                "				margin: 0px;\r\n" +
                "			}\r\n" +
                "          pre {\r\n" +
                "               white-space: pre-wrap;\r\n" +
                "               word-wrap: break-word;\r\n" +
                "               word-break: break-all;\r\n" +
                "           }\r\n" +
                "		</style>\r\n" +
                "	</head>\r\n" +
                "	<body>\r\n" +
                "		<div id=\"Canvas\">\r\n" +
                "			<pre>" + content.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;").Replace("\'", "&#x27;").Replace("/", "&#x2F;") + "</pre>\r\n" +
                "		</div>\r\n" +
                "	</body>\r\n" +
                "</html>";
            return html;
        }

        /// <summary>
        /// WebBrowser的JSON数据
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static string GetDocumentTextWithJson(string json, bool isMock)
        {
            string path = "";
            if (isMock)
            {
                try
                {
                    path = Path.GetTempPath() + "MockBJ.png";
                    Properties.Resources.MockBJ.Save(path);
                }
                catch (Exception e)
                {
                    FiddlerApplication.Log.LogString(e.StackTrace);
                }
            }

            bool isDefaultExpand = FiddlerApplication.Prefs.GetBoolPref("fiddlerex.webbrowser.json.isdefaultexpand", true);

            #region json着色
            string html = "<!DOCTYPE html>\r\n<html>\r\n" +
            "	<head>\r\n" +
            //"		<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n" +
            "       <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n" +
            "       <meta charset=\"utf-8\">\r\n" +
            "		<meta name=\"viewport\" content=\"width=device-width, minimum-scale=0.1\">\r\n" +
            "		<title>JsonViewer</title>\r\n" +
            "		<style>\r\n" +
            "			body {\r\n" +
            "				font-family: Lucida Console, Georgia;\r\n" +
            "				font-size: 13px;\r\n" +
            "				background-color: #ECECEC;\r\n" +
            "				color: #000000;\r\n" +
            //"				border: solid 1px #CECECE;\r\n" +
            "               margin: 0px;\r\n" +
            "               background: #ECECEC url(\"" + path.Replace("\\", "/") + "\")\r\n" +
            "			}\r\n" +
            "			.ObjectBrace {\r\n" +
            "				color: #00AA00;\r\n" +
            "				font-weight: bold;\r\n" +
            "			}\r\n" +
            "			.ArrayBrace {\r\n" +
            "				color: #0033FF;\r\n" +
            "				font-weight: bold;\r\n" +
            "			}\r\n" +
            "			.PropertyName {\r\n" +
            "				color: #CC0000;\r\n" +
            "				font-weight: bold;\r\n" +
            "			}\r\n" +
            "			.String {\r\n" +
            "               white-space: pre-wrap;\r\n" +
            "               word-wrap: break-word;\r\n" +
            "               word-break: break-all;\r\n" +
            "				color: #007777;\r\n" +
            "			}\r\n" +
            "			.Number {\r\n" +
            "				color: #AA00AA;\r\n" +
            "			}\r\n" +
            "			.Boolean {\r\n" +
            "				color: #0000FF;\r\n" +
            "			}\r\n" +
            "			.Function {\r\n" +
            "				color: #AA6633;\r\n" +
            "				text-decoration: italic;\r\n" +
            "			}\r\n" +
            "			.Null {\r\n" +
            "				color: #0000FF;\r\n" +
            "			}\r\n" +
            "			.Comma {\r\n" +
            "				color: #000000;\r\n" +
            "				font-weight: bold;\r\n" +
            "			}\r\n" +
            "			code, pre {\r\n" +
            "				padding: 0 3px 2px;\r\n" +
            "				font-family: Menlo,Monaco,Consolas,\"Courier New\",monospace;\r\n" +
            "				font-size: 12px;\r\n" +
            "				color: #333333;\r\n" +
            "				-webkit-border-radius: 3px;\r\n" +
            "				-moz-border-radius: 3px;\r\n" +
            "				border-radius: 3px;\r\n" +
            "			}\r\n" +
            "		</style>\r\n" +
            "	</head>\r\n" +
            "	<body onload=\"Process()\">\r\n" +
            "		<div id=\"Canvas\">Please wait...</div>\r\n" +
            "	</body>\r\n" +
            "	<script>\r\n" +
            "		var expandDeep = 0;\r\n" +
            "		window.SINGLE_TAB = \"  \";\r\n" +
            //"		window.ImgCollapsed = \"" + Application.StartupPath.Replace("\\", "/") + "/Collapsed.gif\";\r\n" +
            //"		window.ImgExpanded = \"" + Application.StartupPath.Replace("\\", "/") + "/Expanded.gif\";\r\n" +
            "		window.ImgCollapsed = \"\";\r\n" +
            "		window.ImgExpanded = \"\";\r\n" +
            "		window.QuoteKeys = true;\r\n" +
            "		function $id(id){ return document.getElementById(id); }\r\n" +
            "		function IsArray(obj) {\r\n" +
            "		  return  obj && \r\n" +
            "				  typeof obj === 'object' && \r\n" +
            "				  typeof obj.length === 'number' &&\r\n" +
            "				  !(obj.propertyIsEnumerable('length'));\r\n" +
            "		}\r\n" +
            "\r\n" +
            "       function showCount(ta, length){\r\n" +
            "        var span = document.createElement(\"span\");\r\n" +
            "            span.style.fontStyle = \"italic\";\r\n" +
            "            span.style.color = \"#aaa\";\r\n" +
            "            span.innerText = length + \" items\";\r\n" +
            "            ta.parentNode.appendChild(span);\r\n" +
            "       }\r\n" +
            "       function hideCount(ta)\r\n" +
            "       {\r\n" +
            "           if (ta.parentNode.lastChild.tagName.toLowerCase () == \"span\")" +
            "            ta.parentNode.removeChild(ta.parentNode.lastChild);\r\n" +
            "       }\r\n" +
            "		function Process(){\r\n" +
            "		  SetTab();\r\n" +
            "		  window.IsCollapsible = true; //显示控制收起/展开 //$id(\"CollapsibleView\").checked;\r\n" +
            "		  var json = \"" + json + "\"; \r\n" +
            "		  var html = \"\";\r\n" +
            "		  try{\r\n" +
            "			if(json == \"\"){ json = \"\\\"\\\"\";return;}\r\n" +
            "			var obj = eval(\"[\"+json+\"]\");\r\n" +
            "			html = ProcessObject(obj[0], 0, false, false, false);\r\n" +
            "			$id(\"Canvas\").innerHTML = \"<PRE class='CodeContainer'>\"+html+\"</PRE>\";\r\n" +
            "		  }catch(e){\r\n" +
            "			alert(\"JSON数据格式不正确:\\n\"+e.message);\r\n" +
            "			$id(\"Canvas\").innerHTML = json;\r\n" +
            "		  }\r\n" +
            "		}\r\n" +
            "		\r\n" +
            "		window._dateObj = new Date();\r\n" +
            "		window._regexpObj = new RegExp();\r\n" +
            "		function ProcessObject(obj, indent, addComma, isArray, isPropertyContent){\r\n" +
            "		  var html = \"\";\r\n" +
            "		  var comma = (addComma) ? \"<span class='Comma'>,</span> \" : \"\"; \r\n" +
            "		  var type = typeof obj;\r\n" +
            "		  var clpsHtml =\"\";\r\n" +
            "		  if(IsArray(obj)){\r\n" +
            "			if(obj.length == 0){\r\n" +
            "			  html += GetRow(indent, \"<span class='ArrayBrace'>[ ]</span>\"+comma, isPropertyContent);\r\n" +
            "			}else{\r\n" +
            "			  clpsHtml = " + (isDefaultExpand ? "\"<span><img style='cursor:pointer' src=\\\"\"+window.ImgExpanded+\"\\\" onClick=\\\"ExpImgClicked(this)\\\" onmouseover=\\\"showCount(this, \" + obj.length + \")\\\" onmouseout=\\\"hideCount(this)\\\"/></span><span class='collapsible'>\";\r\n" : "\"<span><img style='cursor:pointer' src=\\\"\"+window.ImgCollapsed+\"\\\" onClick=\\\"ExpImgClicked(this)\\\" onmouseover=\\\"showCount(this, \" + obj.length + \")\\\" onmouseout=\\\"hideCount(this)\\\"/></span><span class='collapsible' style='display: none;'>\";\r\n") +
            "			  html += GetRow(indent, \"<span class='ArrayBrace'>[</span>\"+clpsHtml, isPropertyContent);\r\n" +
            "			  for(var i = 0; i < obj.length; i++){\r\n" +
            "				html += ProcessObject(obj[i], indent + 1, i < (obj.length - 1), true, false);\r\n" +
            "			  }\r\n" +
            "			  clpsHtml = window.IsCollapsible ? \"</span>\" : \"\";\r\n" +
            "			  html += GetRow(indent, clpsHtml+\"<span class='ArrayBrace'>]</span>\"+comma);\r\n" +
            "			}\r\n" +
            "		  }else if(type == 'object'){\r\n" +
            "			if (obj == null){\r\n" +
            "				html += FormatLiteral(\"null\", \"\", comma, indent, isArray, \"Null\");\r\n" +
            "			}else if (obj.constructor == window._dateObj.constructor) { \r\n" +
            "				html += FormatLiteral(\"new Date(\" + obj.getTime() + \") /*\" + obj.toLocaleString()+\"*/\", \"\", comma, indent, isArray, \"Date\"); \r\n" +
            "			}else if (obj.constructor == window._regexpObj.constructor) {\r\n" +
            "				html += FormatLiteral(\"new RegExp(\" + obj + \")\", \"\", comma, indent, isArray, \"RegExp\"); \r\n" +
            "			}else{\r\n" + 
            "			  expandDeep = expandDeep + 1;\r\n" +
            "			  var numProps = 0;\r\n" +
            "			  for(var prop in obj) numProps++;\r\n" +
            "			  if(numProps == 0){\r\n" +
            "				html += GetRow(indent, \"<span class='ObjectBrace'>{ }</span>\"+comma, isPropertyContent);\r\n" + 
            "			  }else{\r\n" +
            "			  if(expandDeep > 1){\r\n" +
            "				clpsHtml = " + (isDefaultExpand ? "\"<span><img style='cursor:pointer' src=\\\"\"+window.ImgExpanded+\"\\\" onClick=\\\"ExpImgClicked(this)\\\" onmouseover=\\\"showCount(this, \" + GetLength(obj) + \")\\\" onmouseout=\\\"hideCount(this)\\\"/></span><span class='collapsible'>\";\r\n" : "\"<span><img style='cursor:pointer' src=\\\"\"+window.ImgCollapsed+\"\\\" onClick=\\\"ExpImgClicked(this)\\\" onmouseover=\\\"showCount(this, \" + GetLength(obj) + \")\\\" onmouseout=\\\"hideCount(this)\\\"/></span><span class='collapsible' style='display: none;'>\";\r\n") +
            "             } else {\r\n" +
            "              clpsHtml = \"<span><img style='cursor:pointer' src=\\\"\"+window.ImgExpanded+\"\\\" onClick=\\\"ExpImgClicked(this)\\\" onmouseover=\\\"showCount(this, \" + GetLength(obj) + \")\\\" onmouseout=\\\"hideCount(this)\\\"/></span><span class='collapsible'>\";\r\n" +
            "               }\r\n" +
            "				html += GetRow(indent, \"<span class='ObjectBrace'>{</span>\"+clpsHtml, isPropertyContent);\r\n" +
            "				var j = 0;\r\n" +
            "				for(var prop in obj){\r\n" +
            "				  var quote = window.QuoteKeys ? \"\\\"\" : \"\";\r\n" +
            "				  html += GetRow(indent + 1, \"<span class='PropertyName'>\"+quote+prop+quote+\"</span>: \"+ProcessObject(obj[prop], indent + 1, ++j < numProps, false, true));\r\n" +
            "				}\r\n" +
            "				clpsHtml = window.IsCollapsible ? \"</span>\" : \"\";\r\n" +
            "				html += GetRow(indent, clpsHtml+\"<span class='ObjectBrace'>}</span>\"+comma);\r\n" +
            "			  }\r\n" +
            "			}\r\n" +
            "		  }else if(type == 'number'){\r\n" +
            "			html += FormatLiteral(obj, \"\", comma, indent, isArray, \"Number\");\r\n" +
            "		  }else if(type == 'boolean'){\r\n" +
            "			html += FormatLiteral(obj, \"\", comma, indent, isArray, \"Boolean\");\r\n" +
            "		  }else if(type == 'function'){\r\n" +
            "			if (obj.constructor == window._regexpObj.constructor) {\r\n" +
            "				html += FormatLiteral(\"new RegExp(\" + obj + \")\", \"\", comma, indent, isArray, \"RegExp\"); \r\n" +
            "			}else{\r\n" +
            "				obj = FormatFunction(indent, obj);\r\n" +
            "				html += FormatLiteral(obj, \"\", comma, indent, isArray, \"Function\");\r\n" +
            "			}\r\n" +
            "		  }else if(type == 'undefined'){\r\n" +
            "			html += FormatLiteral(\"undefined\", \"\", comma, indent, isArray, \"Null\");\r\n" +
            "		  }else{\r\n" +
            "			html += FormatLiteral(obj.toString().split(\"\\\\\").join(\"\\\\\\\\\").split('\"').join('\\\\\"'), \"\\\"\", comma, indent, isArray, \"String\");\r\n" +
            "		  }\r\n" +
            "		  return html;\r\n" +
            "		}\r\n" +
            "		\r\n" +
            "       function GetLength(obj){\r\n" +
            "         var arr = [];\r\n" +
		    "         for(var item in obj)\r\n" +
            "           {\r\n" +
            "               arr.push(item);\r\n" +
            "           }\r\n" +
            "           return arr.length;\r\n" +
            "       }\r\n" +
            "		function FormatLiteral(literal, quote, comma, indent, isArray, style){\r\n" +
            "		  if(typeof literal == 'string')\r\n" +
            "			literal = literal.split(\"<\").join(\"&lt;\").split(\">\").join(\"&gt;\");\r\n" +
            "		  var str = \"<span class='\"+style+\"'>\"+quote+literal+quote+comma+\"</span>\";\r\n" +
            "		  if(isArray) str = GetRow(indent, str);\r\n" +
            "		  return str;\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function FormatFunction(indent, obj){\r\n" +
            "		  var tabs = \"\";\r\n" +
            "		  for(var i = 0; i < indent; i++) tabs += window.TAB;\r\n" +
            "		  var funcStrArray = obj.toString().split(\"\\n\");\r\n" +
            "		  var str = \"\";\r\n" +
            "		  for(var i = 0; i < funcStrArray.length; i++){\r\n" +
            "			str += ((i==0)?\"\":tabs) + funcStrArray[i] + \"\\n\";\r\n" +
            "		  }\r\n" +
            "		  return str;\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function GetRow(indent, data, isPropertyContent){\r\n" +
            "		  var tabs = \"\";\r\n" +
            "		  for(var i = 0; i < indent && !isPropertyContent; i++) tabs += window.TAB;\r\n" +
            "		  if(data != null && data.length > 0 && data.charAt(data.length-1) != \"\\n\")\r\n" +
            "			data = data+\"\\n\";\r\n" +
            "		  return tabs+data;                       \r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function CollapsibleViewClicked(){\r\n" +
            "		  $id(\"CollapsibleViewDetail\").style.visibility = $id(\"CollapsibleView\").checked ? \"visible\" : \"hidden\";\r\n" +
            "		  Process();\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function QuoteKeysClicked(){\r\n" +
            "		  window.QuoteKeys = $id(\"QuoteKeys\").checked;\r\n" +
            "		  Process();\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function CollapseAllClicked(){\r\n" +
            "		  EnsureIsPopulated();\r\n" +
            "		  TraverseChildren($id(\"Canvas\"), function(element){\r\n" +
            "			if(element.className == 'collapsible'){\r\n" +
            "			  MakeContentVisible(element, false);\r\n" +
            "			}\r\n" +
            "		  }, 0);\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function ExpandAllClicked(){\r\n" +
            "		  EnsureIsPopulated();\r\n" +
            "		  TraverseChildren($id(\"Canvas\"), function(element){\r\n" +
            "			if(element.className == 'collapsible'){\r\n" +
            "			  MakeContentVisible(element, true);\r\n" +
            "			}\r\n" +
            "		  }, 0);\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function MakeContentVisible(element, visible){\r\n" +
            "		  var img = element.previousSibling.firstChild;\r\n" +
            "		  if(!!img.tagName && img.tagName.toLowerCase() == \"img\"){\r\n" +
            "			element.style.display = visible ? 'inline' : 'none';\r\n" +
            "			element.previousSibling.firstChild.src = visible ? window.ImgExpanded : window.ImgCollapsed;\r\n" +
            "		  }\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function TraverseChildren(element, func, depth){\r\n" +
            "		  for(var i = 0; i < element.childNodes.length; i++){\r\n" +
            "			TraverseChildren(element.childNodes[i], func, depth + 1);\r\n" +
            "		  }\r\n" +
            "		  func(element, depth);\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function ExpImgClicked(img){\r\n" +
            "		  var container = img.parentNode.nextSibling;\r\n" +
            "		  if(!container) return;\r\n" +
            "		  var disp = \"none\";\r\n" +
            "		  var src = window.ImgCollapsed;\r\n" +
            "		  if(container.style.display == \"none\"){\r\n" +
            "			  disp = \"inline\";\r\n" +
            "			  src = window.ImgExpanded;\r\n" +
            "		  }\r\n" +
            "		  container.style.display = disp;\r\n" +
            "		  img.src = src;\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function CollapseLevel(level){\r\n" +
            "		  EnsureIsPopulated();\r\n" +
            "		  TraverseChildren($id(\"Canvas\"), function(element, depth){\r\n" +
            "			if(element.className == 'collapsible'){\r\n" +
            "			  if(depth >= level){\r\n" +
            "				MakeContentVisible(element, false);\r\n" +
            "			  }else{\r\n" +
            "				MakeContentVisible(element, true);  \r\n" +
            "			  }\r\n" +
            "			}\r\n" +
            "		  }, 0);\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function SetTab(){\r\n" +
            "		  var tabSize = 2; //json缩进单位\r\n" +
            "		  window.TAB = MultiplyString(tabSize, window.SINGLE_TAB);\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function EnsureIsPopulated(){\r\n" +
            "		  if(!$id(\"Canvas\").innerHTML) Process();\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function MultiplyString(num, str){\r\n" +
            "		  var sb =[];\r\n" +
            "		  for(var i = 0; i < num; i++){\r\n" +
            "			sb.push(str);\r\n" +
            "		  }\r\n" +
            "		  return sb.join(\"\");\r\n" +
            "		}\r\n" +
            "\r\n" +
            "		function SelectAllClicked(){\r\n" +
            "		  if(!!document.selection && !!document.selection.empty) {\r\n" +
            "			document.selection.empty();\r\n" +
            "		  } else if(window.getSelection) {\r\n" +
            "			var sel = window.getSelection();\r\n" +
            "			if(sel.removeAllRanges) {\r\n" +
            "			  window.getSelection().removeAllRanges();\r\n" +
            "			}\r\n" +
            "		  }\r\n" +
            "		  var range = \r\n" +
            "			  (!!document.body && !!document.body.createTextRange)\r\n" +
            "\r\n" +
            "				  ? document.body.createTextRange()\r\n" +
            "\r\n" +
            "				  : document.createRange();\r\n" +
            "		  if(!!range.selectNode)\r\n" +
            "			range.selectNode($id(\"Canvas\"));\r\n" +
            "		  else if(range.moveToElementText)\r\n" +
            "			range.moveToElementText($id(\"Canvas\"));\r\n" +
            "		  if(!!range.select)\r\n" +
            "			range.select($id(\"Canvas\"));\r\n" +
            "		  else\r\n" +
            "			window.getSelection().addRange(range);\r\n" +
            "		}\r\n" +
            "	</script>\r\n" +
            "</html>";
            #endregion

            return html;
        }

        public static void CompareSession(Session session1, Session session2)
        {
            string mergePath = GetFiddlerExBinDirectory() + "WinMergeU.exe";
            if (!File.Exists(mergePath))
            {
                MessageBox.Show(mergePath + " 文件不存在！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            List<Session> sessionList = new List<Session>();
            sessionList.Add(session1);
            sessionList.Add(session2);
            string sid1 = "";
            string sid2 = "";
            foreach (Session os in sessionList)
            {
                StringBuilder sb = new StringBuilder();
                bool isDiffHeaders = FiddlerApplication.Prefs.GetBoolPref("fiddlerex.func.isdiffheaders", false);
                sb.AppendLine(os.fullUrl);
                sb.AppendLine();

                if (isDiffHeaders)
                {
                    string heahers = os.RequestHeaders.ToString();
                    sb.AppendLine("RequestHeaders:");
                    sb.AppendLine(heahers);
                    sb.AppendLine();
                }
                
                string request = os.GetRequestBodyAsString();
                request = ConvertJsonString(request, true);
                sb.AppendLine("RequestBody:");
                sb.AppendLine(request);
                sb.AppendLine();

                if (isDiffHeaders)
                {
                    string heahers = os.ResponseHeaders.ToString();
                    sb.AppendLine("ResponseHeaders:");
                    sb.AppendLine(heahers);
                    sb.AppendLine();
                }

                string response = os.GetResponseBodyAsString();
                response = ConvertJsonString(response, true);
                sb.AppendLine("ResponseBody:");
                sb.AppendLine(response);

                string extend = GetJsonValueWithPath(request, "clientInfo.extend");
                string platform = "";
                if (extend != "")
                {
                    try
                    {
                        platform = extend.Split(',')[2].Split('^')[1]; //设备名称
                    }
                    catch (Exception)
                    {

                    }
                }

                // 文件名
                string fileName = GetFiddlerExCompareDirectory() + "S_" + os.id + "_" + platform + "_" + os.host.Replace(":", "_") + ".txt";
                // 创建文件，准备写入
                FileStream fs = File.Open(fileName,
                        FileMode.Create,
                        FileAccess.Write);
                StreamWriter wr = new StreamWriter(fs);

                wr.WriteLine(sb);

                // 关闭文件
                wr.Flush();
                wr.Close();
                fs.Close();

                if (sid1 != "")
                {
                    sid2 = fileName;
                }
                else
                {
                    sid1 = fileName;
                }
            }

            string cmd = "\"" + mergePath + "\" " + "\"" + sid1 + "\" " + "\"" + sid2 + "\"";

            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
            p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
            p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
            p.StartInfo.CreateNoWindow = true;//不显示程序窗口
            p.Start();//启动程序

            //向cmd窗口发送输入信息
            p.StandardInput.WriteLine(cmd + "&exit");

            p.StandardInput.AutoFlush = true;
        }

        /// <summary>
        /// 自定义执行控件事件
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="EventName"></param>
        /// <param name="e"></param>
        public static void CallObjectEvent(Object obj, string EventName, EventArgs e = null)
        {
            //建立一个类型      
            //Type t = typeof(obj.GetType);  
            Type t = Type.GetType(obj.GetType().AssemblyQualifiedName);
            //产生方法      
            MethodInfo m = t.GetMethod(EventName, BindingFlags.NonPublic | BindingFlags.Instance);
            //参数赋值。传入函数      
            //获得参数资料  
            ParameterInfo[] para = m.GetParameters();
            //根据参数的名字，拿参数的空值。  
            //参数对象      
            object[] p = new object[1];
            if (e == null)
                p[0] = Type.GetType(para[0].ParameterType.BaseType.FullName).GetProperty("Empty");
            else
                p[0] = e;
            //调用  
            m.Invoke(obj, p);
            return;
        }

        public static string GetFiddlerExBinDirectory()
        {
            string binPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Bin\\";
            if (!Directory.Exists(binPath))
            {
                FiddlerApplication.Log.LogString(binPath + "目录不存在！");
                return "";
            }
            return binPath;
        }

        public static string GetFiddlerExCompareDirectory()
        {
            string comparePath = Application.StartupPath + "\\FiddlerInspectorsEx\\Compare\\";
            if (!Directory.Exists(comparePath))
            {
                FiddlerApplication.Log.LogString(comparePath + "目录不存在！");
                return "";
            }
            return comparePath;
        }

        public static string GetFiddlerExDataDirectory()
        {
            string dataPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Data\\";
            if (!Directory.Exists(dataPath))
            {
                FiddlerApplication.Log.LogString(dataPath + "目录不存在！");
                return "";
            }
            return dataPath;
        }

        public static string GetFiddlerExExportDirectory()
        {
            string exportPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Export\\";
            if (!Directory.Exists(exportPath))
            {
                FiddlerApplication.Log.LogString(exportPath + "目录不存在！");
                return "";
            }
            return exportPath;
        }

        public static string GetFiddlerExLogDirectory()
        {
            string logPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Log\\";
            if (!Directory.Exists(logPath))
            {
                FiddlerApplication.Log.LogString(logPath + "目录不存在！");
                return "";
            }
            return logPath;
        }

        /// <summary>
        /// 创建插件目录
        /// </summary>
        public static void CreateFiddlerExDirectory()
        {
            string binPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Bin";
            string comparePath = Application.StartupPath + "\\FiddlerInspectorsEx\\Compare";
            string dataPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Data";
            string exportPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Export";
            string logPath = Application.StartupPath + "\\FiddlerInspectorsEx\\Log";

            try
            {
                if (!Directory.Exists(binPath))
                    Directory.CreateDirectory(binPath);
                if (!Directory.Exists(comparePath))
                    Directory.CreateDirectory(comparePath);
                if (!Directory.Exists(dataPath))
                    Directory.CreateDirectory(dataPath);
                if (!Directory.Exists(exportPath))
                    Directory.CreateDirectory(exportPath);
                if (!Directory.Exists(logPath))
                    Directory.CreateDirectory(logPath);
            }
            catch (Exception e)
            {
                FiddlerApplication.Log.LogString(e.StackTrace);
            }
        }

        /// <summary>
        /// 设置JSON树展示
        /// </summary>
        /// <param name="treeView"></param>
        /// <param name="sText"></param>
        /// <returns></returns>
        public static bool SetJSON(TreeView treeView, string sText)
        {
            if (sText.Trim() == "")
            {
                treeView.Nodes.Clear();
                return false;
            }

            TreeNode inTreeNode = new TreeNode("JSON");
            uint iNodeCount = 0;
            try
            {
                Clear(treeView);
                if (sText.StartsWith(")]}',\n"))
                {
                    sText = sText.Substring(6);
                }
                int index = sText.IndexOf('{');
                int num3 = sText.IndexOf("[");
                int length = sText.Length;
                char ch = '\0';
                if ((index > -1) && (index < length))
                {
                    ch = '}';
                    length = index;
                }
                if ((num3 > -1) && (num3 < length))
                {
                    ch = ']';
                    length = num3;
                }
                int num5 = sText.Length;
                switch (ch)
                {
                    case '}':
                    case ']':
                        num5 = sText.LastIndexOf(ch) + 1;
                        if (num5 < 1)
                        {
                            FiddlerApplication.Log.LogString("SetJSON: The body does not contain valid JSON text; matching end missing.");
                            return false;
                        }
                        break;
                }
                if ((num5 - length) > 0)
                {
                    sText = sText.Substring(length, num5 - length);
                }
                object o = JSON.JsonDecode(sText, out JSON.JSONParseErrors errors);
                if ((o == null) && (sText != "null"))
                {
                    FiddlerApplication.Log.LogString(string.Format("SetJSON: Invalid text at position {0}.", length + errors.iErrorIndex));
                    return false;
                }
                if (!string.IsNullOrEmpty(errors.sWarningText))
                {
                    FiddlerApplication.Log.LogString(string.Format("SetJSON: WARNING: {0}", errors.sWarningText));
                    return false;
                }
                else
                {
                    //FiddlerApplication.Log.LogString("SetJSON: JSON parsing completed.");
                }
                ChainNodes(-1, inTreeNode, o, false, ref iNodeCount);
            }
            catch (Exception exception)
            {
                FiddlerApplication.Log.LogString("SetJSON: " + exception.Message);
                return false;
            }
            try
            {
                BeginUpdate(treeView);
                treeView.Nodes.Add(inTreeNode);
                treeView.Nodes[0].ExpandAll();
                //if (iNodeCount < 0x7d0)
                //{
                //    treeView.Nodes[0].ExpandAll();
                //}
                //else
                //{
                //    treeView.Nodes[0].Expand();
                //}
                treeView.Nodes[0].EnsureVisible();

                //SetTreeNodeToolTipText(treeView, treeView.Tag);

                EndUpdate(treeView);
            }
            finally
            {
                EndUpdate(treeView);
            }
            return true;
        }

        internal static void ChainNodes(int index, TreeNode inTreeNode, object o, bool bParentIsArray, ref uint iNodeCount)
        {
            if (o is ArrayList)
            {
                ArrayList list = o as ArrayList;
                if (list.Count > 0)
                {
                    if (bParentIsArray && index != -1)
                    {
                        inTreeNode = inTreeNode.Nodes.Add("[" + "]");
                        iNodeCount++;
                    }
                    //foreach (object obj2 in list)
                    //{
                    //    this.ChainNodes(inTreeNode, obj2, true, ref iNodeCount);
                    //}
                    for (int i = 0; i < list.Count; i++)
                    {
                        object obj2 = list[i];
                        ChainNodes(i, inTreeNode, obj2, true, ref iNodeCount);
                    }
                }
            }
            else if (o is Hashtable)
            {
                Hashtable d = o as Hashtable;
                if (d.Count > 0)
                {
                    if (bParentIsArray && (d.Count > 1) && index != -1)
                    {
                        inTreeNode = inTreeNode.Nodes.Add("{" + index + "}");
                        iNodeCount++;
                    }
                    foreach (DictionaryEntry entry in new SortedList(d))
                    {
                        string sText = entry.Key.ToString();
                        TreeNode oTN = new TreeNode();
                        SetTreeNodeLimitedText(oTN, sText);
                        inTreeNode.Nodes.Add(oTN);
                        iNodeCount++;
                        ChainNodes(-1, oTN, entry.Value, false, ref iNodeCount);
                    }
                }
            }
            else
            {
                string str;
                if (o == null)
                {
                    str = "(null)";
                }
                else if (o is DateTime)
                {
                    str = ((DateTime)o).ToString("r");
                }
                else if (o is double)
                {
                    str = ((double)o).ToString("R", CultureInfo.InvariantCulture);
                }
                else
                {
                    str = o.ToString();
                }
                if (bParentIsArray)
                {
                    TreeNode node2 = new TreeNode();
                    SetTreeNodeLimitedText(node2, str);
                    inTreeNode.Nodes.Add(node2);
                    iNodeCount++;
                }
                else
                {
                    string treeNodeFullText = GetTreeNodeFullText(inTreeNode);

                    //inTreeNode.ImageIndex = -1;
                    //string sTxt = string.Format("{0}{1}{2}", treeNodeFullText, treeNodeFullText.Contains("=") ? ", " : " : ", str);
                    //if(o is string)
                    //{
                    //    inTreeNode.ImageKey = "blue";
                    //    sTxt = string.Format("{0}{1}\"{2}\"", treeNodeFullText, treeNodeFullText.Contains("=") ? ", " : " : ", str);
                    //}
                    //SetTreeNodeLimitedText(inTreeNode, sTxt);

                    SetTreeNodeLimitedText(inTreeNode, string.Format("{0}{1}{2}", treeNodeFullText, treeNodeFullText.Contains("=") ? ", " : "=", str));
                }
            }
        }

        internal static void SetTreeNodeLimitedText(TreeNode oTN, string sText)
        {
            string str = sText;

            if (str.Length > 0x103)
            {
                str = Utilities.TrimTo(str, 0x102) + "…";
            }
            oTN.Text = str;

            if (str != sText)
            {
                oTN.Tag = sText; //即Node节点提示文字
            }
        }

        internal static string GetTreeNodeFullText(TreeNode oTN)
        {
            if (oTN.Tag == null)
            {
                return oTN.Text;
            }
            return (oTN.Tag as string);
        }

        internal static void BeginUpdate(TreeView treeView)
        {
            treeView.BeginUpdate();
            treeView.SuspendLayout();
        }

        internal static void EndUpdate(TreeView treeView)
        {
            treeView.EndUpdate();
            treeView.ResumeLayout();
        }

        internal static void Clear(TreeView treeView)
        {
            BeginUpdate(treeView);
            treeView.Nodes.Clear();
            EndUpdate(treeView);
        }
    }
}
